#ifndef WINGS_H
#define WINGS_H
#include <QtWidgets>
#include <QRegularExpressionMatch>
#include <QtCore/private/qzipreader_p.h>
#include <QtCore/private/qzipwriter_p.h>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QtConcurrent/QtConcurrent>
#include <windows.h>

typedef  unsigned short MatchingMode;
typedef  unsigned short Function_Flag;
#define MatchingMode_Simple (01)
#define MatchingMode_Exact (02)
#define MatchingMode_Similarity (03)
#define FUNCTION_FIND (21)
#define FUNCTION_GZIP (22)
#define FUNCTION_PZIP (23)
#define FUNCTION_MKPATH (24)
#define FUNCTION_MKDIR (25)

#define SCROPED_LOCAL_FIND(paths, keywords, suffixs, modes, receive){\
    QScopedPointer<Nlwingsing> T(new Nlwingsing);\
    QString KEY = QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate);\
    T->appendInfo(paths, keywords, suffixs, modes, KEY);\
    T->start(KEY);\
    T->captrueData(KEY, (receive));\
};


#define SCROPED_LOCAL_SIMILARITY_FIND(paths, keywords, suffixs, receive, similarity){\
    QScopedPointer<Nlwingsing> T(new Nlwingsing);\
    QString KEY = QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate);\
    T->appendInfo(paths, keywords, suffixs, MatchingMode_Similarity, KEY, similarity);\
    T->start(KEY);\
    T->captrueData(KEY, (receive));\
};


#define SCROPED_ZIP_G(paths, dir, filter){\
    QScopedPointer<Nlwingsing> T(new Nlwingsing);\
    T->appendInfo(paths, dir, filter, FUNCTION_GZIP);\
    T->start();\
    T->wait_p();\
};


#define SCROPED_ZIP_P(paths, dir){\
    QScopedPointer<Nlwingsing> T(new Nlwingsing);\
    T->appendInfo(paths, dir, NULL, FUNCTION_PZIP);\
    T->start();\
    T->wait_p();\
};


#define SCROPED_PATH_MAKE(paths){\
    QScopedPointer<Nlwingsing> T(new Nlwingsing);\
    T->appendInfo(paths, NULL, NULL, FUNCTION_MKPATH);\
    T->start();\
    T->wait_p();\
};


#define SCROPED_DIR_MAKE(paths, rmlast){\
    QScopedPointer<Nlwingsing> T(new Nlwingsing);\
    T->appendInfo(paths, rmlast, NULL, FUNCTION_MKDIR);\
    T->start();\
    T->wait_p();\
};


class Nlwingsing : public QThread{

    Q_OBJECT

public:

    Nlwingsing(){};

    static void makeDirectory(QString directory, bool rmlast=false);

    static void makeSignalFile(QString file);

    static void ZipGet(QString zpath, QString dir = NULL, QList<QString> filter = {});

    static void ZipPush(QString zpath, QString dir = NULL);

    static QString jigsawPath(QString path, bool esuffix=true, bool simplify=false);

    static const std::string QMultiByteToWideChar(const char *bcc);

    static const std::string QWideCharToMultiByte(const std::string gbc);

    void start(QString lockey="", QThread::Priority priority = InheritPriority);

    template<typename str_path, typename str_keyword, typename str_suffix>
    void appendInfo(str_path paths, str_keyword keywords, str_suffix suffixs, MatchingMode modes, QString lockey, double similarity=80){
        QList<QVariant> pathli; QList<QVariant> keywordli; QList<QVariant> suffixli; QList<QVariant> modeli;
        fallapart(pathli, QVariant(paths));
        fallapart(keywordli, QVariant(keywords));
        fallapart(suffixli, QVariant(suffixs));
        fallapart(modeli, QVariant(modes));
        setProperty("function-type", FUNCTION_FIND);
        setProperty("similarity-num", similarity);
        infomap[lockey]["matching-path"].append(pathli);
        infomap[lockey]["matching-keyword"].append(keywordli);
        infomap[lockey]["matching-suffix"].append(suffixli);
        infomap[lockey]["matching-mode"].append(modeli);

    }

    template<typename str_path, typename multiarg1, typename multiarg2>
    void appendInfo(str_path path, multiarg1 arg1, multiarg2 arg2, Function_Flag flag){
        setProperty("function-type", flag);
        if (flag == FUNCTION_MKPATH)
        {
            infomap["make-path"]["paths"].append(path);
        }
        else if (flag == FUNCTION_MKDIR)
        {
            infomap["make-dir"]["paths"].append(path);
            infomap["make-dir"]["rmlast"].append(arg1);
        }
        else if (flag == FUNCTION_GZIP)
        {
            infomap["zip-g"]["paths"].append(path);
            infomap["zip-g"]["dir"].append(arg1);
            infomap["zip-g"]["filter"].append(arg2);
        }
        else if (flag == FUNCTION_PZIP)
        {
            infomap["zip-p"]["paths"].append(path);
            infomap["zip-p"]["dir"].append(arg1);
        }
    }

    QList<QString> captrueData(QString lockey="");

    void captrueData(QString lockey, QStringList &data);

    void captrueData(QString lockey, QString &data);

    void captrueData(QString lockey, QMap<QString,QString> &data);

    void wait_p();

    static uint similarity(QString data, QString compare)
    {
        double totalscore = 0;
        if (!data.isEmpty() && !compare.isEmpty())
        {
            int equalindex = 0;
            QList<int> equalindexli;
            double depandeblescore;
            int loop;
            bool blast = false;
            if (data.size() > compare.size())
            {
                loop = data.size();
                depandeblescore = (double)100 / data.size();
            }
            else
            {
                loop = compare.size();
                depandeblescore = (double)100 / compare.size();
            }
            double despondmentscore = depandeblescore / 2;
            for(int index = 0; index < loop; index++)
            {
                QChar sgarg1;
                QChar sgarg2;
                if (index < data.length()) sgarg1 = data[index];
                if (index < compare.length()) sgarg2 = compare[index];
                if (data.contains(sgarg2))
                {
                    int indexof = data.indexOf(sgarg2);
                    /*当 equalindex 为 0 并且 indexof 大于 0 时，即 equalindex 未发生过赋值，则将 indexof - 1 赋值给它，即获取前一个项索引
                      如果项不连续了，那就取当前索引值*/
                    if (!equalindex && indexof) equalindex = indexof - 1;

                    if (equalindex > indexof && sgarg2 == data[equalindex + 1])
                    {
                        int fishnet = equalindex;
                        while (equalindex > indexof)
                        {
                            //如果idnexof索引值为equalindex之前的元素的索引值，则 equalindex + 1，跳过该元素，向后取正确的索引值
                            indexof = data.indexOf(sgarg2, fishnet);
                            fishnet++;
                        }
                    }
                    if (equalindex + 1 == indexof && equalindex != 0)
                    {
                        totalscore += depandeblescore;
                        blast = true;
                    }
                    else
                    {
                        if (!equalindexli.contains(indexof)) totalscore += despondmentscore;
                    }
                    equalindex = indexof;
                    equalindexli.append(indexof);
                }
            }
            if (blast) totalscore += depandeblescore;
            if (ceil(totalscore) <= 100) totalscore = ceil(totalscore);
        }
        return totalscore;
    }

private:
    QMap<QString, QMap<QString, QList<QVariant>>> infomap;
    QMap<QString, QList<QString>> result;
    QString runningKey;

    void run();

    void fd_pathloop(std::string path, QList<QVariant> keywords, QList<QVariant> suffixs, QVariant mode, QList<QString> &fishhoo, bool isvariant_fish=false);

    void mc_keyword(std::string _zpath, QList<QVariant> kws, MatchingMode mode, QList<QString> &fishhook, bool isvariant_fish);

    bool islist(QVariant &var){
        return (var.metaType().id() == QMetaType::QStringList);
    }

    void fallapart(QList<QVariant> &get, QVariant data)
    {
        if (data.metaType().id() == QMetaType::QStringList)
        {
            QList<QVariant> loopdata = data.toList();
            if (!loopdata.isEmpty())
            {
                foreach(QVariant T, loopdata)
                {
                    if (data.metaType().id() == QMetaType::QStringList)
                    {
                        fallapart(get, T);
                    }
                    else
                    {
                        get.append(data);
                    }
                }
            }
        }
        else if (data.metaType().id() == QMetaType::LongLong)
        {
            if (data.toLongLong()) get.append(data);
        }
        else
        {
            get.append(data);
        }
    }
};

#endif // WINGS_H
